function Joint(gl, value, parts) {
	this.vertexBuffer = gl.createBuffer();
	this.normalBuffer = gl.createBuffer();
	this.colorsBuffer = gl.createBuffer();
	this.indexBuffer = gl.createBuffer();
	/* ref.numbers of the two connected parts. Note that the default -1 is illegal here, you must not omit these properties. Both parts have to be created earlier. */
	this.p1 = -1;
	this.p2 = -1;
	
	this.p1value;
	this.p2value;
	/* rotation: can be used to enforce specific orientation of the second part (p2) relative to the first part (p1). Orientation can influence some of the effectors/receptors and can be used as growing direction while creature is being constructed. */
	this.rx = 0.0;
	this.ry = 0.0;
	this.rz = 0.0;
	/* delta option: if you specify any value for dx, all three deltas are used as displacement applied to the second part (p2) relative to the first part (p1). Local coordinate system of p1 is first rotated (as defined by [rx,ry,rz]) and then translated by [dx,dy,dz]. This technique allows you to define relative placement of parts. Without this delta option, absolute part positioning is used (as defined by the coordinates [x,y,z] of the part). */
	this.dx = 0.0;
	this.dy = 0.0;
	this.dz = 0.0;
	/* stiffness */
	this.stif = 1;
	/* rotation stiffness */
	this.rotstif = 1;
	/* stamina */
	this.stam = 0.25;
	/* general purpose "info" field */
	this.i = "";

	if (value.length > 0) {
		var position = "0";

		var tmp = value.split(":");
		var data = tmp[1];

		if (tmp.length > 2) // if there was more ":"
			for (i = 2; i < tmp.length; i++)
				data += ":" + tmp[i];

		var info = data.split(",");

		for (var i = 0; i < info.length; i++) {
			var str = info[i];
			if (str.indexOf("\"") > -1) {
				while ((str.split("\"").length % 2) == 1)
					str += "," + info[++i];
			}

			str = str.trim();

			if (str == "")
				position = nextJoint(position);
			else {
				var value;

				if ((str.indexOf("\"") > 1 || str.indexOf("\"") == -1)
						&& str.indexOf("=") > -1) {
					position = str.split("=")[0];
					value = str.split("=")[1];
				} else {
					position = nextJoint(position);
					value = str;
				}

				switch (position) {
				case 'p1':
					this.p1 = parseFloat(value);
					this.p1value = parts[this.p1];
					break;
				case 'p2':
					this.p2 = parseFloat(value);
					this.p2value = parts[this.p2];
					break;
				case 'rx':
					this.rx = parseFloat(value);
					break;
				case 'ry':
					this.ry = parseFloat(value);
					break;
				case 'rz':
					this.rz = parseFloat(value);
					break;
				case 'dx':
					this.dx = parseFloat(value);
					break;
				case 'dy':
					this.dy = parseFloat(value);
					break;
				case 'dz':
					this.dz = parseFloat(value);
					break;
				case 'stif':
					this.stif = value;
					break;
				case 'rotstif':
					this.rotstif = value;
					break;
				case 'stam':
					this.stam = value;
					break;
				case 'i':
					this.i = value;
					break;
				default:
					alert("error");
				}
			}
		}
		
		var X = this.dx;
		var Y = this.dy;
		var Z = this.dz;


		if (this.rz != 0)
		{
			var newX = X * Math.cos(this.rz) - Y * Math.sin(this.rz);
			var newY = X * Math.sin(this.rz) + Y * Math.cos(this.rz);
			Y = newY;
			X = newX;
		}
		if (this.ry != 0)
		{
			var newZ = Z * Math.cos(this.ry) - X * Math.sin(this.ry);
			var newX = Z * Math.sin(this.ry) + X * Math.cos(this.ry);
			X = newX;
			Z = newZ;
		}
		
		if (this.rx != 0)
		{
			var newY = Y * Math.cos(this.rx) - Z * Math.sin(this.rx);
			var newZ = Y * Math.sin(this.rx) + Z * Math.cos(this.rx);
			Y = newY;
			Z = newZ;
		}
		
		
		

		
		
		
		if (X != 0 || Y != 0 || Z != 0)
		{
			this.p2value.x = this.p1value.x + X;
			this.p2value.y = this.p1value.y + Y;
			this.p2value.z = this.p1value.z + Z;
		}
		
		var latitudeBands = 40;
	    var radius = 1;

	    var vertexPositionData = [];
	    var normalData = [];
	    var textureCoordData = [];
	    for (var latNumber = 0; latNumber <= latitudeBands; latNumber++) {
	      var theta = 4 * latNumber * Math.PI / latitudeBands;
	      var sinTheta = Math.sin(theta);
	      var cosTheta = Math.cos(theta);
	      
	        var x = sinTheta;
	        var y = cosTheta;

	        //alert(x + " " + y);
	        
	        normalData.push(x);
	        normalData.push(y);
	        normalData.push(0);
	        vertexPositionData.push(radius * x);
	        vertexPositionData.push(radius * y);
	        vertexPositionData.push(0);
	    
	        normalData.push(x);
	        normalData.push(y);
	        normalData.push(-1);
	        vertexPositionData.push(radius * x);
	        vertexPositionData.push(radius * y);
	        vertexPositionData.push(-1);
	    
	    }


	    var indexData = [];
	    for (var latNumber = 0; latNumber < latitudeBands; latNumber++) {
	        var first = latNumber;
	        
	        //alert(first);
	        
	        indexData.push(first % latitudeBands);
	        indexData.push((first + 1) % latitudeBands);
	        indexData.push((first + 2) % latitudeBands);

	        indexData.push((first + 1) % latitudeBands);
	        indexData.push((first + 2) % latitudeBands);
	        indexData.push((first + 3) % latitudeBands);
	    }
	    //alert(indexData.length);

	    gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
	    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositionData), gl.STATIC_DRAW);
	    this.vertexBuffer.itemSize = 3;
	    this.vertexBuffer.numItems = vertexPositionData.length / 3;

	    gl.bindBuffer(gl.ARRAY_BUFFER, this.normalBuffer);
	    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);
	    this.normalBuffer.itemSize = 3;
	    this.normalBuffer.numItems = normalData.length / 3;

	    gl.bindBuffer(gl.ARRAY_BUFFER, this.colorsBuffer);
	    var colors = [
	      [1.0, 0.0, 0.0, 1.0],     // Front face
	    ];
	    var unpackedColors = [];
	    for (var i = 0; i < normalData.length / 3; i++) {
	      var color = colors[0];
	      for (var j = 0; j < 4; j++) {
	        unpackedColors = unpackedColors.concat(color);
	      }
	    }
	    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(unpackedColors), gl.STATIC_DRAW);
	    this.colorsBuffer.itemSize = 4;
	    this.colorsBuffer.numItems = normalData.length / 3;

	    
	    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
	    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STREAM_DRAW);
	    this.indexBuffer.itemSize = 1;
	    this.indexBuffer.numItems = indexData.length;
	
	}

}